#include <doors/udp.h>
#include "coappdu.h"
#include "coappdu.i"
#include "coapconst.h"
/*
 0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |Ver| T |  OC   |      Code     |          Message ID           |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |   Options (if any) ...
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |   Payload (if any) ...
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/


/************** GET **************/
Uint16 CoapPeer :: GET :: decode (Message* msg)
{
	Frame data = ((UdpSAP::Dtind *) msg)->data;

	//version isn't needed to decode (only 1)
	//type isn't needed to decode (only con)
	Uint8 optioncount = data.read(0) & 0xF0;
	//code isn't needed to decode (only GET)
	Uint16 tmp= data.read(2);
	messageID= tmp << 8 & data.read(3);
	//go trough all options
	int delta= 0;
	int offset= 4;
	for(int i= 0; i < optioncount; i++)
	{
		//find option number
		int optionnumber= (data.read(offset) >> 4) - delta;
		//find length
		int length= data.read(offset) & 0xF0;
		if(length == 15)
		{
			length+= data.read(++offset);
		}
		//save option
		switch(optionnumber)
		{
		case OPT_URIPATH:
			uripath.clear();
			for(int ocket= 0; ocket < length; ocket++)
			{
				uripath+= data.read(offset+ocket);
			}
			break;
		}
		//set up next delta
		delta = data.read(offset) >> 4;
		//set up next offset
		offset+= length + 1;
	}

	addr = ((UdpSAP::Dtind *) msg)->source;	
	return data.length();
}

Message* CoapPeer :: GET :: encode (void)
{
	UdpSAP::Dtreq *dtreq = new UdpSAP::Dtreq;
	//version, type, option count
	Uint8 version= COAP_VERSION;
	Uint8 type= TYPE_CON;
	Uint8 optioncount= 0;
	if(!uripath.empty()) optioncount++;
	Uint8 header= version << 6 | type << 4 | optioncount;
	dtreq->data.putLast(header);
	//code
	dtreq->data.putLast(CODE_GET);
	//message id
	dtreq->data.putLast((const Byte*) &messageID, 2);
	//options - uri-path
	if(!uripath.empty())
	{
		//delta 0x9
		if(uripath.length() < 15)
		{
			Uint8 option= OPT_URIPATH << 4 | uripath.length();
			dtreq->data.putLast(option);
		}
		else
		{
			dtreq->data.putLast(OPT_URIPATH << 4 | 0x0F);
			dtreq->data.putLast(uripath.length()-15);
		}
		//copy option
		dtreq->data.putLast((const Byte*) uripath.data(), uripath.length());
	}
	//destination address
	dtreq->dest = addr;	
	return dtreq;
}

/************** DEL **************/
Uint16 CoapPeer :: DEL :: decode (Message* msg)
{
	Frame data = ((UdpSAP::Dtind *) msg)->data;

	//version isn't need to decode (only 1)
	//type isn't need to decode (only con)
	//option count
	Uint8 optioncount = data.read(0) & 0xF0;
	//code isn't need to decode (only DELETE)
	//message id
	Uint16 tmp= data.read(2);
	messageID= tmp << 8 & data.read(3);
	//go trough all options
	int delta= 0;
	int offset= 4;
	for(int i= 0; i < optioncount; i++)
	{
		//find option number
		int optionnumber= (data.read(offset) >> 4) - delta;
		//find length
		int length= data.read(offset) & 0xF0;
		if(length == 15)
		{
			length+= data.read(++offset);
		}
		//save option
		switch(optionnumber)
		{
		case OPT_URIPATH: 
			uripath.clear();
			for(int ocket= 0; ocket < length; ocket++)
			{
				uripath+= data.read(offset+ocket);
			}
			break;
		}
		//set up next delta
		delta = data.read(offset) >> 4;
		//set up next offset
		offset+= length + 1;
	}

	addr = ((UdpSAP::Dtind *) msg)->source;	
	return data.length();
}

Message* CoapPeer :: DEL :: encode (void)
{
	UdpSAP::Dtreq *dtreq = new UdpSAP::Dtreq;
	//version, type, option count
	Uint8 version= COAP_VERSION;
	Uint8 type= TYPE_CON;
	Uint8 optioncount= 0;
	if(!uripath.empty()) optioncount++;
	Uint8 header= version << 6 | type << 4 | optioncount;
	dtreq->data.putLast(header);
	//code
	dtreq->data.putLast(CODE_DELETE);
	//message id
	dtreq->data.putLast((const Byte*) &messageID, 2);
	//options - uri-path
	if(!uripath.empty())
	{
		//delta 0x9
		if(uripath.length() < 15)
		{
			Uint8 option= OPT_URIPATH << 4 | uripath.length();
			dtreq->data.putLast(option);
		}
		else
		{
			dtreq->data.putLast(OPT_URIPATH << 4 | 0x0F);
			dtreq->data.putLast(uripath.length()-15);
		}
		//copy option
		dtreq->data.putLast((const Byte*) uripath.data(), uripath.length());
	}
	//destination address
	dtreq->dest = addr;	
	return dtreq;
}

/************** PUT **************/
Uint16 CoapPeer :: PUT :: decode (Message* msg)
{
	Frame data = ((UdpSAP::Dtind *) msg)->data;

	//version isn't need to decode (only 1)
	//type isn't need to decode (only con)
	//option count
	Uint8 optioncount = data.read(0) & 0xF0;
	//code isn't need to decode (only PUT)
	//message id
	Uint16 tmp= data.read(2);
	messageID= tmp << 8 & data.read(3);
	//go trough all options
	int delta= 0;
	int offset= 4;
	for(int i= 0; i < optioncount; i++)
	{
		//find option number
		int optionnumber= (data.read(offset) >> 4) - delta;
		//find length
		int length= data.read(offset) & 0xF0;
		if(length == 15)
		{
			length+= data.read(++offset);
		}
		//save option
		switch(optionnumber)
		{
		case OPT_URIPATH:
			uripath.clear();
			for(int ocket= 0; ocket < length; ocket++)
			{
				uripath+= data.read(offset+ocket);
			}
			break;
		}
		//set up next delta
		delta = data.read(offset) >> 4;
		//set up next offset
		offset+= length + 1;
	}
	
	//payload - is this right?
	Byte* tmpbuf= (Byte*) data;
	payload.putLast(tmpbuf + offset, data.length() - offset);


	addr = ((UdpSAP::Dtind *) msg)->source;	
	return data.length();
}

Message* CoapPeer :: PUT :: encode (void)
{
	UdpSAP::Dtreq *dtreq = new UdpSAP::Dtreq;
	//version, type, option count
	Uint8 version= COAP_VERSION;
	Uint8 type= TYPE_CON;
	Uint8 optioncount= 0;
	if(!uripath.empty()) optioncount++;
	Uint8 header= version << 6 | type << 4 | optioncount;
	dtreq->data.putLast(header);
	//code
	dtreq->data.putLast(CODE_PUT);
	//message id
	dtreq->data.putLast((const Byte*) &messageID, 2);
	//options - uri-path
	if(!uripath.empty())
	{
		//delta 0x9
		if(uripath.length() < 15)
		{
			Uint8 option= OPT_URIPATH << 4 | uripath.length();
			dtreq->data.putLast(option);
		}
		else
		{
			dtreq->data.putLast(OPT_URIPATH << 4 | 0x0F);
			dtreq->data.putLast(uripath.length()-15);
		}
		//copy option
		dtreq->data.putLast((const Byte*) uripath.data(), uripath.length());
	}
	
	//payloade
	dtreq->data.combine(payload);
	
	//destination address
	dtreq->dest = addr;	
	return dtreq;
}

/************** ACK **************/
Uint16 CoapPeer :: ACK :: decode (Message* msg)
{
	Frame data = ((UdpSAP::Dtind *) msg)->data;

	//version isn't needed to decode
	//type isn't needed to decode (only ack)
	//option count insn't need to decode (always 0 in this implementation)
	//code
	code = data.read(1);
	//message id
	Uint16 tmp= data.read(2);
	messageID= tmp << 8 & data.read(3);

	//payload - is this right?
	int offset= 4;
	Byte* tmpbuf= (Byte*) data;
	payload.putLast(tmpbuf + offset, data.length() - offset);

	addr = ((UdpSAP::Dtind *) msg)->source;	
	return data.length();
}
	
Message* CoapPeer :: ACK :: encode (void)
{
	UdpSAP::Dtreq *dtreq = new UdpSAP::Dtreq;
	//version, type, option count
	Uint8 version= COAP_VERSION;
	Uint8 type= TYPE_ACK;
	Uint8 optioncount= 0;
	//no options
	Uint8 header= version << 6 | type << 4 | optioncount;
	dtreq->data.putLast(header);
	//code
	dtreq->data.putLast(code);
	//message id
	dtreq->data.putLast((const Byte*) &messageID, 2);
	//no options
	
	//payloade
	dtreq->data.combine(payload);
	
	//destination address
	dtreq->dest = addr;	
	return dtreq;
}


/************** IDENTIFY **************/
Sint16 CoapPeer :: identify (Message *msg) 
{
	//identify according code value
	Uint8 code = ((UdpSAP::Dtind *) msg)->data.read(1);
	switch(code)
	{
	case CODE_GET:
		return get;
	case CODE_PUT:
		return put;
	case CODE_DELETE:
		return del;
	default:
		if(code >= 64 && code <= 191)
			return ack;
	}
	return other;
}




